<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>Hilo 使用记录 | 小熊的技术文档</title>
    <meta name="generator" content="VuePress 1.8.2">
    <link rel="icon" href="/fav.ico">
    <link rel="stylesheet" href="/css/katex.min.css">
    <link rel="stylesheet" href="/css/github-markdown.min.css">
    <meta name="description" content="衣带渐宽终不悔，为伊消得人憔悴">
    
    <link rel="preload" href="/assets/css/0.styles.e6449353.css" as="style"><link rel="preload" href="/assets/js/app.9e067b79.js" as="script"><link rel="preload" href="/assets/js/2.983eb755.js" as="script"><link rel="preload" href="/assets/js/60.b47b75bb.js" as="script"><link rel="prefetch" href="/assets/js/10.79548333.js"><link rel="prefetch" href="/assets/js/11.31600f80.js"><link rel="prefetch" href="/assets/js/12.62bd3528.js"><link rel="prefetch" href="/assets/js/13.de8b1ace.js"><link rel="prefetch" href="/assets/js/14.f5db1e75.js"><link rel="prefetch" href="/assets/js/15.bf827d4d.js"><link rel="prefetch" href="/assets/js/16.cc9a1a73.js"><link rel="prefetch" href="/assets/js/17.2cfaefeb.js"><link rel="prefetch" href="/assets/js/18.3af7782b.js"><link rel="prefetch" href="/assets/js/19.639f7e7b.js"><link rel="prefetch" href="/assets/js/20.dc862f59.js"><link rel="prefetch" href="/assets/js/21.916e1685.js"><link rel="prefetch" href="/assets/js/22.d7a955f4.js"><link rel="prefetch" href="/assets/js/23.078391ef.js"><link rel="prefetch" href="/assets/js/24.bb460a5a.js"><link rel="prefetch" href="/assets/js/25.d69f2326.js"><link rel="prefetch" href="/assets/js/26.6da7ea48.js"><link rel="prefetch" href="/assets/js/27.82e23d91.js"><link rel="prefetch" href="/assets/js/28.9073bbec.js"><link rel="prefetch" href="/assets/js/29.639259a4.js"><link rel="prefetch" href="/assets/js/3.e594e5b2.js"><link rel="prefetch" href="/assets/js/30.b49c622d.js"><link rel="prefetch" href="/assets/js/31.92f6c8b3.js"><link rel="prefetch" href="/assets/js/32.42419088.js"><link rel="prefetch" href="/assets/js/33.c82e2ab8.js"><link rel="prefetch" href="/assets/js/34.381de37e.js"><link rel="prefetch" href="/assets/js/35.5e86d478.js"><link rel="prefetch" href="/assets/js/36.31f218ce.js"><link rel="prefetch" href="/assets/js/37.0d287b3f.js"><link rel="prefetch" href="/assets/js/38.1324cf44.js"><link rel="prefetch" href="/assets/js/39.de6bdb51.js"><link rel="prefetch" href="/assets/js/4.440c4dd9.js"><link rel="prefetch" href="/assets/js/40.a22c9c27.js"><link rel="prefetch" href="/assets/js/41.4637d617.js"><link rel="prefetch" href="/assets/js/42.db815e2b.js"><link rel="prefetch" href="/assets/js/43.f0955a92.js"><link rel="prefetch" href="/assets/js/44.7d5faddf.js"><link rel="prefetch" href="/assets/js/45.a88ffc33.js"><link rel="prefetch" href="/assets/js/46.883caa71.js"><link rel="prefetch" href="/assets/js/47.6f2cfd60.js"><link rel="prefetch" href="/assets/js/48.ea25654e.js"><link rel="prefetch" href="/assets/js/49.f38c23a0.js"><link rel="prefetch" href="/assets/js/5.e8844f36.js"><link rel="prefetch" href="/assets/js/50.e03dd8e9.js"><link rel="prefetch" href="/assets/js/51.f6160d52.js"><link rel="prefetch" href="/assets/js/52.4daa8322.js"><link rel="prefetch" href="/assets/js/53.b30992e9.js"><link rel="prefetch" href="/assets/js/54.209f17e1.js"><link rel="prefetch" href="/assets/js/55.4f1dd95b.js"><link rel="prefetch" href="/assets/js/56.147ea3e8.js"><link rel="prefetch" href="/assets/js/57.5823e0e2.js"><link rel="prefetch" href="/assets/js/58.772320f9.js"><link rel="prefetch" href="/assets/js/59.5ab55a80.js"><link rel="prefetch" href="/assets/js/6.54e1cc95.js"><link rel="prefetch" href="/assets/js/61.0cd5a012.js"><link rel="prefetch" href="/assets/js/62.35eb5453.js"><link rel="prefetch" href="/assets/js/63.d31f2118.js"><link rel="prefetch" href="/assets/js/64.03d35d7c.js"><link rel="prefetch" href="/assets/js/65.8bdc633f.js"><link rel="prefetch" href="/assets/js/66.dbbe8867.js"><link rel="prefetch" href="/assets/js/67.228613b5.js"><link rel="prefetch" href="/assets/js/68.d10a2687.js"><link rel="prefetch" href="/assets/js/69.7903847f.js"><link rel="prefetch" href="/assets/js/7.f5ab00eb.js"><link rel="prefetch" href="/assets/js/70.11ee4e27.js"><link rel="prefetch" href="/assets/js/8.95b39934.js"><link rel="prefetch" href="/assets/js/9.26cfd48c.js">
    <link rel="stylesheet" href="/assets/css/0.styles.e6449353.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/" class="home-link router-link-active"><!----> <span class="site-name">小熊的技术文档</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/front-end/" class="nav-link">
  🎨前端
</a></div><div class="nav-item"><a href="/back-end/" class="nav-link">
  💻后端
</a></div><div class="nav-item"><a href="/practice/" class="nav-link router-link-active">
  🚀实战
</a></div><div class="nav-item"><a href="/office/" class="nav-link">
  🏢办公
</a></div><div class="nav-item"><a href="/general/" class="nav-link">
  🍓通用
</a></div><div class="nav-item"><a href="/paper/" class="nav-link">
  🐸论文
</a></div><div class="nav-item"><a href="/general/fast.html" class="nav-link">
  ⚡快速笔记
</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="🦉近期重点" class="dropdown-title"><span class="title">🦉近期重点</span> <span class="arrow down"></span></button> <button type="button" aria-label="🦉近期重点" class="mobile-dropdown-title"><span class="title">🦉近期重点</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/back-end/python.html" class="nav-link">
  🐇python常用模块
</a></li><li class="dropdown-item"><!----> <a href="/practice/zrender.html" class="nav-link">
  🌹zrender源码解析
</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="⭐️资源" class="dropdown-title"><span class="title">⭐️资源</span> <span class="arrow down"></span></button> <button type="button" aria-label="⭐️资源" class="mobile-dropdown-title"><span class="title">⭐️资源</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="https://www.birdiesearch.com/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  小鸟搜索
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://salttiger.com/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  每天一本编程书
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://gitee.com/docmirror/dev-sidecar" target="_blank" rel="noopener noreferrer" class="nav-link external">
  开发者边车
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></div></div> <!----></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/front-end/" class="nav-link">
  🎨前端
</a></div><div class="nav-item"><a href="/back-end/" class="nav-link">
  💻后端
</a></div><div class="nav-item"><a href="/practice/" class="nav-link router-link-active">
  🚀实战
</a></div><div class="nav-item"><a href="/office/" class="nav-link">
  🏢办公
</a></div><div class="nav-item"><a href="/general/" class="nav-link">
  🍓通用
</a></div><div class="nav-item"><a href="/paper/" class="nav-link">
  🐸论文
</a></div><div class="nav-item"><a href="/general/fast.html" class="nav-link">
  ⚡快速笔记
</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="🦉近期重点" class="dropdown-title"><span class="title">🦉近期重点</span> <span class="arrow down"></span></button> <button type="button" aria-label="🦉近期重点" class="mobile-dropdown-title"><span class="title">🦉近期重点</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/back-end/python.html" class="nav-link">
  🐇python常用模块
</a></li><li class="dropdown-item"><!----> <a href="/practice/zrender.html" class="nav-link">
  🌹zrender源码解析
</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="⭐️资源" class="dropdown-title"><span class="title">⭐️资源</span> <span class="arrow down"></span></button> <button type="button" aria-label="⭐️资源" class="mobile-dropdown-title"><span class="title">⭐️资源</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="https://www.birdiesearch.com/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  小鸟搜索
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://salttiger.com/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  每天一本编程书
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://gitee.com/docmirror/dev-sidecar" target="_blank" rel="noopener noreferrer" class="nav-link external">
  开发者边车
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></div></div> <!----></nav>  <ul class="sidebar-links"><li><a href="/practice/deepL.html" class="sidebar-link">使用pytorch进行深度学习</a></li><li><a href="/practice/Hilo.html" aria-current="page" class="active sidebar-link">Hilo 使用记录</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/practice/Hilo.html#使用记录" class="sidebar-link">使用记录</a></li><li class="sidebar-sub-header"><a href="/practice/Hilo.html#使用-hilo-开发-flappy-bird" class="sidebar-link">使用 Hilo 开发 Flappy Bird</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/practice/Hilo.html#源文件结构" class="sidebar-link">源文件结构</a></li><li class="sidebar-sub-header"><a href="/practice/Hilo.html#预加载图片" class="sidebar-link">预加载图片</a></li><li class="sidebar-sub-header"><a href="/practice/Hilo.html#初始化舞台" class="sidebar-link">初始化舞台</a></li><li class="sidebar-sub-header"><a href="/practice/Hilo.html#场景分析" class="sidebar-link">场景分析</a></li><li class="sidebar-sub-header"><a href="/practice/Hilo.html#游戏背景" class="sidebar-link">游戏背景</a></li><li class="sidebar-sub-header"><a href="/practice/Hilo.html#准备场景" class="sidebar-link">准备场景</a></li><li class="sidebar-sub-header"><a href="/practice/Hilo.html#结束场景" class="sidebar-link">结束场景</a></li><li class="sidebar-sub-header"><a href="/practice/Hilo.html#创建小鸟" class="sidebar-link">创建小鸟</a></li><li class="sidebar-sub-header"><a href="/practice/Hilo.html#创建障碍" class="sidebar-link">创建障碍</a></li><li class="sidebar-sub-header"><a href="/practice/Hilo.html#碰撞检测和得分" class="sidebar-link">碰撞检测和得分</a></li><li class="sidebar-sub-header"><a href="/practice/Hilo.html#监控游戏过程" class="sidebar-link">监控游戏过程</a></li><li class="sidebar-sub-header"><a href="/practice/Hilo.html#场景切换" class="sidebar-link">场景切换</a></li><li class="sidebar-sub-header"><a href="/practice/Hilo.html#玩家交互" class="sidebar-link">玩家交互</a></li><li class="sidebar-sub-header"><a href="/practice/Hilo.html#小结" class="sidebar-link">小结</a></li></ul></li></ul></li><li><a href="/practice/canvas.html" class="sidebar-link">canvas 绘制</a></li><li><a href="/practice/react.html" class="sidebar-link">React + AntD 实战后台管理</a></li><li><a href="/practice/zrender.html" class="sidebar-link">ZRender 源码解析</a></li><li><a href="/practice/search.html" class="sidebar-link">基于 node.js 的全文搜索</a></li><li><a href="/practice/phaser.html" class="sidebar-link">使用phaser开发战旗游戏</a></li><li><a href="/practice/medicine.html" class="sidebar-link">小儿用药</a></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h1 id="hilo-使用记录"><a href="#hilo-使用记录" class="header-anchor">#</a> Hilo 使用记录</h1> <blockquote><p><a href="https://github.com/hiloteam/Hilo" target="_blank" rel="noopener noreferrer">Hilo<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> 是阿里巴巴集团开发的一款 HTML5 跨终端游戏解决方案，可以帮助开发者快速创建 HTML5 游戏。</p></blockquote> <h2 id="使用记录"><a href="#使用记录" class="header-anchor">#</a> 使用记录</h2> <p>使用<code>npm install hilojs --save</code>进行安装</p> <h2 id="使用-hilo-开发-flappy-bird"><a href="#使用-hilo-开发-flappy-bird" class="header-anchor">#</a> 使用 Hilo 开发 Flappy Bird</h2> <p>Flappy Bird 是一款前不久风靡世界的休闲小游戏。虽然它难度超高，但是游戏本身却非常简单。下面我们就使用 Hilo 来快速开发 HTML5 版的 Flappy Bird。</p> <h3 id="源文件结构"><a href="#源文件结构" class="header-anchor">#</a> 源文件结构</h3> <p>大家可以先下载 <a href="https://wws.lanzous.com/iXpmKgja8oh" target="_blank" rel="noopener noreferrer">Flappy Bird 的项目源文件<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>作为参考，以下是整个项目的文件结构：</p> <div class="language-bash extra-class"><pre class="language-bash"><code>flappybird/
├── index.html //游戏主页面
├── js/
│   ├── game.js //游戏主模块
│   ├── Asset.js //素材加载类
│   ├── ReadyScene.js //准备场景
│   ├── OverScene.js //结束场景
│   ├── Bird.js //小鸟类
│   ├── Holdbacks.js //障碍类
│   ├── hilo-standalone.js //hilo独立版
└── images/
</code></pre></div><h3 id="预加载图片"><a href="#预加载图片" class="header-anchor">#</a> 预加载图片</h3> <p>为了让玩家有更流畅的游戏体验，图片素材一般需要预先加载。Hilo 提供了一个队列下载工具 LoadQueue，使用它可以预加载图片素材。如下所示，在 Asset 类中，我们定义了 load 方法：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token function-variable function">load</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">var</span> resources <span class="token operator">=</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>id<span class="token operator">:</span><span class="token string">'bg'</span><span class="token punctuation">,</span> src<span class="token operator">:</span><span class="token string">'images/bg.png'</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">{</span>id<span class="token operator">:</span><span class="token string">'ground'</span><span class="token punctuation">,</span> src<span class="token operator">:</span><span class="token string">'images/ground.png'</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">{</span>id<span class="token operator">:</span><span class="token string">'ready'</span><span class="token punctuation">,</span> src<span class="token operator">:</span><span class="token string">'images/ready.png'</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">{</span>id<span class="token operator">:</span><span class="token string">'over'</span><span class="token punctuation">,</span> src<span class="token operator">:</span><span class="token string">'images/over.png'</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">{</span>id<span class="token operator">:</span><span class="token string">'number'</span><span class="token punctuation">,</span> src<span class="token operator">:</span><span class="token string">'images/number.png'</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">{</span>id<span class="token operator">:</span><span class="token string">'bird'</span><span class="token punctuation">,</span> src<span class="token operator">:</span><span class="token string">'images/bird.png'</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">{</span>id<span class="token operator">:</span><span class="token string">'holdback'</span><span class="token punctuation">,</span> src<span class="token operator">:</span><span class="token string">'images/holdback.png'</span><span class="token punctuation">}</span>
    <span class="token punctuation">]</span><span class="token punctuation">;</span>

    <span class="token keyword">this</span><span class="token punctuation">.</span>queue <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Hilo<span class="token punctuation">.</span>LoadQueue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>queue<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>resources<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>queue<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">'complete'</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">onComplete</span><span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>queue<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>从上面代码中可以看到，resources 是我们要下载的图片素材列表，使用 queue.add() 方法把素材列表加入到下载队列中，再使用 queue.start() 方法来启动下载队列。</p> <blockquote><p><strong>提示</strong>：下载队列 LoadQueue 当前仅支持图片等资源的下载，其他资源文件可通过自定义扩展方式实现。具体可参考 API 文档。</p></blockquote> <p>为了获得下载情况，LoadQueue 提供了三个事件：</p> <ul><li><code>load</code> - 当单个资源下载完成时发生</li> <li><code>complete</code> - 当所有资源下载完成时发生</li> <li><code>error</code> - 当某一资源下载出错时发生</li></ul> <p>在这里我们仅监听了 complete 事件。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token function-variable function">onComplete</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>bg <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>queue<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'bg'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>content<span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>ground <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>queue<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'ground'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>content<span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>birdAtlas <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Hilo<span class="token punctuation">.</span>TextureAtlas</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        image<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>queue<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'bird'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>content<span class="token punctuation">,</span>
        frames<span class="token operator">:</span> <span class="token punctuation">[</span>
            <span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">120</span><span class="token punctuation">,</span> <span class="token number">86</span><span class="token punctuation">,</span> <span class="token number">60</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
            <span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">60</span><span class="token punctuation">,</span> <span class="token number">86</span><span class="token punctuation">,</span> <span class="token number">60</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
            <span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">86</span><span class="token punctuation">,</span> <span class="token number">60</span><span class="token punctuation">]</span>
        <span class="token punctuation">]</span><span class="token punctuation">,</span>
        sprites<span class="token operator">:</span> <span class="token punctuation">{</span>
            bird<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">]</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">//删除下载队列的complete事件监听</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>queue<span class="token punctuation">.</span><span class="token function">off</span><span class="token punctuation">(</span><span class="token string">'complete'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">//发送complete事件</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">fire</span><span class="token punctuation">(</span><span class="token string">'complete'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>下载完成后会触发 onComplete 回调方法。我们可以通过 queue.get(id).content 来获取指定 id 的图片素材下载完成后的 Image 对象。 在这里我们创建了游戏中需要用到的素材以及精灵纹理集等。</p> <p>其中纹理集 TextureAtlas 实例由三部分组成：</p> <ul><li><code>image</code> - 纹理集图片。</li> <li><code>frames</code> - 纹理集图片帧序列。每个图片帧由图片在纹理集中的坐标 x/y 和宽高 width/height 组成，即 [x, y, width, height]。</li> <li><code>sprites</code> - 精灵定义。sprites 可包含多个精灵定义。每个精灵由多个 frames 中的图片帧组成，其中数值代表图片帧在 frames 中的索引位置。比如 bird，则由索引为 0、1、2 的图片帧组成。</li></ul> <p>在 game.js 中使用 Asset 类来下载完图片素材后，再调用 initStage 方法初始化舞台：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">this</span><span class="token punctuation">.</span>asset <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">game<span class="token punctuation">.</span>Asset</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>asset<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span>
  <span class="token string">'complete'</span><span class="token punctuation">,</span>
  <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>asset<span class="token punctuation">.</span><span class="token function">off</span><span class="token punctuation">(</span><span class="token string">'complete'</span><span class="token punctuation">)</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">initStage</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span>
<span class="token punctuation">)</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>asset<span class="token punctuation">.</span><span class="token function">load</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</code></pre></div><h3 id="初始化舞台"><a href="#初始化舞台" class="header-anchor">#</a> 初始化舞台</h3> <p>由于我们的图片素材是高清图片，且背景大小为 720x1280。因此，我们设定游戏舞台的大小为 720x1280，并设置其 x 和 y 轴的缩放比例均为 0.5，这样舞台实际的可见大小变为 360x640。最后，我们把 canvas 画布添加到 body 中。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token function-variable function">initStage</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>width <span class="token operator">=</span> <span class="token number">720</span><span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>height <span class="token operator">=</span> <span class="token number">1280</span><span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>scale <span class="token operator">=</span> <span class="token number">0.5</span><span class="token punctuation">;</span>

    <span class="token keyword">var</span> stage <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>stage <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Hilo<span class="token punctuation">.</span>Stage</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        width<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>width<span class="token punctuation">,</span>
        height<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>height<span class="token punctuation">,</span>
        scaleX<span class="token operator">:</span> scale<span class="token punctuation">,</span>
        scaleY<span class="token operator">:</span> scale
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>stage<span class="token punctuation">.</span>canvas<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><blockquote><p><strong>注意</strong>：舞台是一个各种图形、精灵动画等的总载体。所有用 Hilo 创建的可见的对象都必须添加到舞台或其子容器后，才会被渲染和显示出来。</p></blockquote> <p>舞台创建好后，我们需要一个定时器来不断更新和渲染舞台。这里可以使用 Ticker 类：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">//设定舞台刷新频率为60fps</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>ticker <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Hilo<span class="token punctuation">.</span>Ticker</span><span class="token punctuation">(</span><span class="token number">60</span><span class="token punctuation">)</span>
<span class="token comment">//把舞台加入到tick队列</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>ticker<span class="token punctuation">.</span><span class="token function">addTick</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>stage<span class="token punctuation">)</span>
<span class="token comment">//启动ticker</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>ticker<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</code></pre></div><h3 id="场景分析"><a href="#场景分析" class="header-anchor">#</a> 场景分析</h3> <p>如果你玩过原版的 Flappy Bird，就知道此游戏的场景非常简单，大致可以划分以下几个部分：</p> <p>背景 - 背景图和移动的地面是贯穿整个游戏，没有变化的。 准备场景 - 一个简单的游戏提示画面。游戏开始前和失败后重新开始都会进入此场景。 游戏场景 - 障碍物不断的从右往左移动，玩家控制小鸟的飞行。 结束场景 - 游戏失败后，显示得分以及相关按钮等。 接下来，我们就开始用 Hilo 来创建这 4 个场景。</p> <h3 id="游戏背景"><a href="#游戏背景" class="header-anchor">#</a> 游戏背景</h3> <p>由于背景是不变的，为了减少 canvas 的重复绘制，我们采用 DOM+CSS 来设置背景。先创建一个 div，设置其 CSS 背景为游戏背景图片，再把它加入到舞台的 canvas 后面。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token function-variable function">initBackground</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">var</span> bgWidth <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>width <span class="token operator">*</span> <span class="token keyword">this</span><span class="token punctuation">.</span>scale<span class="token punctuation">;</span>
    <span class="token keyword">var</span> bgHeight <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>height <span class="token operator">*</span> <span class="token keyword">this</span><span class="token punctuation">.</span>scale<span class="token punctuation">;</span>
    document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">insertBefore</span><span class="token punctuation">(</span>Hilo<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
      id<span class="token operator">:</span> <span class="token string">'bg'</span><span class="token punctuation">,</span>
      style<span class="token operator">:</span> <span class="token punctuation">{</span>
          position<span class="token operator">:</span> <span class="token string">'absolute'</span><span class="token punctuation">,</span>
          background<span class="token operator">:</span> <span class="token string">'url(images/bg.png) no-repeat'</span><span class="token punctuation">,</span>
          backgroundSize<span class="token operator">:</span> bgWidth <span class="token operator">+</span> <span class="token string">'px, '</span> <span class="token operator">+</span> bgHeight <span class="token operator">+</span> <span class="token string">'px'</span><span class="token punctuation">,</span>
          width<span class="token operator">:</span> bgWidth <span class="token operator">+</span> <span class="token string">'px'</span><span class="token punctuation">,</span>
          height<span class="token operator">:</span> bgHeight <span class="token operator">+</span> <span class="token string">'px'</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>stage<span class="token punctuation">.</span>canvas<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>地面也是背景的一部分，处于画面最下端。地面我们使用可视对象 Bitmap 类。一般的，不需要使用精灵动画的普通图片对象都可使用此类。Bitmap 类只要传入相应的图片 image 参数即可。此外，为了方便查找对象，一般我们都为可视对象取一个合适的 id。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token function-variable function">initBackground</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token comment">/* all previous code here */</span>

    <span class="token keyword">this</span><span class="token punctuation">.</span>ground <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Hilo<span class="token punctuation">.</span>Bitmap</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
      id<span class="token operator">:</span> <span class="token string">'ground'</span><span class="token punctuation">,</span>
      image<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>asset<span class="token punctuation">.</span>ground
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">//放置地面在舞台的最底部</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>ground<span class="token punctuation">.</span>y <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>height <span class="token operator">-</span> <span class="token keyword">this</span><span class="token punctuation">.</span>ground<span class="token punctuation">.</span>height<span class="token punctuation">;</span>

    <span class="token comment">//循环移动地面</span>
    Hilo<span class="token punctuation">.</span>Tween<span class="token punctuation">.</span><span class="token function">to</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>ground<span class="token punctuation">,</span> <span class="token punctuation">{</span>x<span class="token operator">:</span><span class="token operator">-</span><span class="token number">60</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>duration<span class="token operator">:</span><span class="token number">300</span><span class="token punctuation">,</span> loop<span class="token operator">:</span><span class="token boolean">true</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>地面不是静止的。它是从右到左的不断循环的移动着的。我们注意到地面的图片素材比背景要宽一些，而地面图片本身也是一些循环的斜四边形组成的。这样的特性，意味着如果我们把图片从当前位置移动到下一个斜四边形的某一位置时，舞台上的地面会看起来是没有移动过一样。我们找到当地面的 x 轴坐标为 - 60 时，跟 x 轴为 0 时的地面的图形是没有差异的。这样，若地面在 0 到 - 60 之间不断循环变化时，地面就循环移动起来了。</p> <p>Hilo 提供了缓动动画 Tween 类。它的使用也非常简单：</p> <div class="language-js extra-class"><pre class="language-js"><code>Hilo<span class="token punctuation">.</span>Tween<span class="token punctuation">.</span><span class="token function">to</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> newProperties<span class="token punctuation">,</span> params<span class="token punctuation">)</span>
</code></pre></div><ul><li><code>obj</code> - 要缓动的对象。</li> <li><code>newProperties</code> - 指定缓动后对象的属性改变后的新值。这里指定 x 为 - 60，也就是地面运动到 x 为 - 60 的位置。</li> <li><code>params</code> - 指定缓动参数。这里指定了缓动时间 time 为 300 毫秒，loop 表示缓动是不断循环的。</li></ul> <p>Tween 类不会自动运行，也需要加入到 tick 队列才能运行：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">this</span><span class="token punctuation">.</span>ticker<span class="token punctuation">.</span><span class="token function">addTick</span><span class="token punctuation">(</span>Hilo<span class="token punctuation">.</span>Tween<span class="token punctuation">)</span>
</code></pre></div><h3 id="准备场景"><a href="#准备场景" class="header-anchor">#</a> 准备场景</h3> <p>准备场景很简单，由一个 Get Ready！的文字图片和 TAP 提示的图片组成。这里，我们创建一个 ReadyScene 的类，继承自容器类 Container。它的实现只需要把 getready 和 tap 这 2 个 Bitmap 对象创建好并放置在适当的位置即可。而它们的图片素材 image 会传给 ReadyScene 的构造函数。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> ReadyScene <span class="token operator">=</span> Hilo<span class="token punctuation">.</span>Class<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  Extends<span class="token operator">:</span> Hilo<span class="token punctuation">.</span>Container<span class="token punctuation">,</span>
  <span class="token function-variable function">constructor</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">properties</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    ReadyScene<span class="token punctuation">.</span>superclass<span class="token punctuation">.</span><span class="token function">constructor</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> properties<span class="token punctuation">)</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">init</span><span class="token punctuation">(</span>properties<span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>

  <span class="token function-variable function">init</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">properties</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">//准备Get Ready!</span>
    <span class="token keyword">var</span> getready <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Hilo<span class="token punctuation">.</span>Bitmap</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
      image<span class="token operator">:</span> properties<span class="token punctuation">.</span>image<span class="token punctuation">,</span>
      rect<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">508</span><span class="token punctuation">,</span> <span class="token number">158</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>

    <span class="token comment">//开始提示tap</span>
    <span class="token keyword">var</span> tap <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Hilo<span class="token punctuation">.</span>Bitmap</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
      image<span class="token operator">:</span> properties<span class="token punctuation">.</span>image<span class="token punctuation">,</span>
      rect<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">158</span><span class="token punctuation">,</span> <span class="token number">286</span><span class="token punctuation">,</span> <span class="token number">246</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>

    <span class="token comment">//确定getready和tap的位置</span>
    tap<span class="token punctuation">.</span>x <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>width <span class="token operator">-</span> tap<span class="token punctuation">.</span>width<span class="token punctuation">)</span> <span class="token operator">&gt;&gt;</span> <span class="token number">1</span>
    tap<span class="token punctuation">.</span>y <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>height <span class="token operator">-</span> tap<span class="token punctuation">.</span>height <span class="token operator">+</span> <span class="token number">40</span><span class="token punctuation">)</span> <span class="token operator">&gt;&gt;</span> <span class="token number">1</span>
    getready<span class="token punctuation">.</span>x <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>width <span class="token operator">-</span> getready<span class="token punctuation">.</span>width<span class="token punctuation">)</span> <span class="token operator">&gt;&gt;</span> <span class="token number">1</span>
    getready<span class="token punctuation">.</span>y <span class="token operator">=</span> <span class="token punctuation">(</span>tap<span class="token punctuation">.</span>y <span class="token operator">-</span> getready<span class="token punctuation">.</span>height<span class="token punctuation">)</span> <span class="token operator">&gt;&gt;</span> <span class="token number">0</span>

    <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">addChild</span><span class="token punctuation">(</span>tap<span class="token punctuation">,</span> getready<span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div><p>在游戏主文件 game.js 中，实例化 ReadyScene 并添加到舞台 stage 上。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">this</span><span class="token punctuation">.</span>readyScene <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">game<span class="token punctuation">.</span>ReadyScene</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  width<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>width<span class="token punctuation">,</span>
  height<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>height<span class="token punctuation">,</span>
  image<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>asset<span class="token punctuation">.</span>ready<span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addTo</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>stage<span class="token punctuation">)</span>
</code></pre></div><h3 id="结束场景"><a href="#结束场景" class="header-anchor">#</a> 结束场景</h3> <p>结束场景跟准备场景相似。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> OverScene <span class="token operator">=</span> <span class="token punctuation">(</span>ns<span class="token punctuation">.</span>OverScene <span class="token operator">=</span> Hilo<span class="token punctuation">.</span>Class<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  Extends<span class="token operator">:</span> Hilo<span class="token punctuation">.</span>Container<span class="token punctuation">,</span>
  <span class="token function-variable function">constructor</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">properties</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    OverScene<span class="token punctuation">.</span>superclass<span class="token punctuation">.</span><span class="token function">constructor</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> properties<span class="token punctuation">)</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">init</span><span class="token punctuation">(</span>properties<span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>

  <span class="token function-variable function">init</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">properties</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">//Game Over图片文字</span>
    <span class="token keyword">var</span> gameover <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>gameover <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Hilo<span class="token punctuation">.</span>Bitmap</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
      id<span class="token operator">:</span> <span class="token string">'gameover'</span><span class="token punctuation">,</span>
      image<span class="token operator">:</span> properties<span class="token punctuation">.</span>image<span class="token punctuation">,</span>
      rect<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">298</span><span class="token punctuation">,</span> <span class="token number">508</span><span class="token punctuation">,</span> <span class="token number">158</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

    <span class="token comment">//结束面板</span>
    <span class="token keyword">var</span> board <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>board <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Hilo<span class="token punctuation">.</span>Bitmap</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
      id<span class="token operator">:</span> <span class="token string">'board'</span><span class="token punctuation">,</span>
      image<span class="token operator">:</span> properties<span class="token punctuation">.</span>image<span class="token punctuation">,</span>
      rect<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">590</span><span class="token punctuation">,</span> <span class="token number">298</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

    <span class="token comment">//开始按钮</span>
    <span class="token keyword">var</span> startBtn <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>startBtn <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Hilo<span class="token punctuation">.</span>Bitmap</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
      id<span class="token operator">:</span> <span class="token string">'start'</span><span class="token punctuation">,</span>
      image<span class="token operator">:</span> properties<span class="token punctuation">.</span>image<span class="token punctuation">,</span>
      rect<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">590</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">290</span><span class="token punctuation">,</span> <span class="token number">176</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

    <span class="token comment">//等级按钮</span>
    <span class="token keyword">var</span> gradeBtn <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>gradeBtn <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Hilo<span class="token punctuation">.</span>Bitmap</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
      id<span class="token operator">:</span> <span class="token string">'grade'</span><span class="token punctuation">,</span>
      image<span class="token operator">:</span> properties<span class="token punctuation">.</span>image<span class="token punctuation">,</span>
      rect<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">590</span><span class="token punctuation">,</span> <span class="token number">176</span><span class="token punctuation">,</span> <span class="token number">290</span><span class="token punctuation">,</span> <span class="token number">176</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

    <span class="token comment">//玩家当前分数</span>
    <span class="token keyword">var</span> scoreLabel <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>scoreLabel <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Hilo<span class="token punctuation">.</span>BitmapText</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
      id<span class="token operator">:</span> <span class="token string">'score'</span><span class="token punctuation">,</span>
      glyphs<span class="token operator">:</span> properties<span class="token punctuation">.</span>numberGlyphs<span class="token punctuation">,</span>
      scaleX<span class="token operator">:</span> <span class="token number">0.5</span><span class="token punctuation">,</span>
      scaleY<span class="token operator">:</span> <span class="token number">0.5</span><span class="token punctuation">,</span>
      letterSpacing<span class="token operator">:</span> <span class="token number">4</span><span class="token punctuation">,</span>
      text<span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

    <span class="token comment">//玩家最好成绩</span>
    <span class="token keyword">var</span> bestLabel <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>bestLabel <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Hilo<span class="token punctuation">.</span>BitmapText</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
      id<span class="token operator">:</span> <span class="token string">'best'</span><span class="token punctuation">,</span>
      glyphs<span class="token operator">:</span> properties<span class="token punctuation">.</span>numberGlyphs<span class="token punctuation">,</span>
      scaleX<span class="token operator">:</span> <span class="token number">0.5</span><span class="token punctuation">,</span>
      scaleY<span class="token operator">:</span> <span class="token number">0.5</span><span class="token punctuation">,</span>
      letterSpacing<span class="token operator">:</span> <span class="token number">4</span><span class="token punctuation">,</span>
      text<span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

    <span class="token comment">//白色的遮罩效果</span>
    <span class="token keyword">var</span> whiteMask <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>whiteMask <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Hilo<span class="token punctuation">.</span>View</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
      id<span class="token operator">:</span> <span class="token string">'mask'</span><span class="token punctuation">,</span>
      width<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>width<span class="token punctuation">,</span>
      height<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>height<span class="token punctuation">,</span>
      alpha<span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">setBgFill</span><span class="token punctuation">(</span><span class="token string">'#fff'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

    <span class="token comment">//设置各个元素的坐标位置</span>
    board<span class="token punctuation">.</span>x <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>width <span class="token operator">-</span> board<span class="token punctuation">.</span>width<span class="token punctuation">)</span> <span class="token operator">&gt;&gt;</span> <span class="token number">1</span>
    board<span class="token punctuation">.</span>y <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>height <span class="token operator">-</span> board<span class="token punctuation">.</span>height<span class="token punctuation">)</span> <span class="token operator">&gt;&gt;</span> <span class="token number">1</span>
    gameover<span class="token punctuation">.</span>x <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>width <span class="token operator">-</span> gameover<span class="token punctuation">.</span>width<span class="token punctuation">)</span> <span class="token operator">&gt;&gt;</span> <span class="token number">1</span>
    gameover<span class="token punctuation">.</span>y <span class="token operator">=</span> board<span class="token punctuation">.</span>y <span class="token operator">-</span> gameover<span class="token punctuation">.</span>height <span class="token operator">-</span> <span class="token number">20</span>
    startBtn<span class="token punctuation">.</span>x <span class="token operator">=</span> board<span class="token punctuation">.</span>x <span class="token operator">-</span> <span class="token number">5</span>
    startBtn<span class="token punctuation">.</span>y <span class="token operator">=</span> <span class="token punctuation">(</span>board<span class="token punctuation">.</span>y <span class="token operator">+</span> board<span class="token punctuation">.</span>height <span class="token operator">+</span> <span class="token number">20</span><span class="token punctuation">)</span> <span class="token operator">&gt;&gt;</span> <span class="token number">0</span>
    gradeBtn<span class="token punctuation">.</span>x <span class="token operator">=</span> <span class="token punctuation">(</span>startBtn<span class="token punctuation">.</span>x <span class="token operator">+</span> startBtn<span class="token punctuation">.</span>width <span class="token operator">+</span> <span class="token number">20</span><span class="token punctuation">)</span> <span class="token operator">&gt;&gt;</span> <span class="token number">0</span>
    gradeBtn<span class="token punctuation">.</span>y <span class="token operator">=</span> startBtn<span class="token punctuation">.</span>y
    scoreLabel<span class="token punctuation">.</span>x <span class="token operator">=</span> <span class="token punctuation">(</span>board<span class="token punctuation">.</span>x <span class="token operator">+</span> board<span class="token punctuation">.</span>width <span class="token operator">-</span> <span class="token number">140</span><span class="token punctuation">)</span> <span class="token operator">&gt;&gt;</span> <span class="token number">0</span>
    scoreLabel<span class="token punctuation">.</span>y <span class="token operator">=</span> board<span class="token punctuation">.</span>y <span class="token operator">+</span> <span class="token number">90</span>
    bestLabel<span class="token punctuation">.</span>x <span class="token operator">=</span> scoreLabel<span class="token punctuation">.</span>x
    bestLabel<span class="token punctuation">.</span>y <span class="token operator">=</span> scoreLabel<span class="token punctuation">.</span>y <span class="token operator">+</span> <span class="token number">105</span>

    <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">addChild</span><span class="token punctuation">(</span>
      gameover<span class="token punctuation">,</span>
      board<span class="token punctuation">,</span>
      startBtn<span class="token punctuation">,</span>
      gradeBtn<span class="token punctuation">,</span>
      scoreLabel<span class="token punctuation">,</span>
      bestLabel<span class="token punctuation">,</span>
      whiteMask
    <span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div><p>结束场景显示的时候，不仅需要显示玩家的得分，出现的时候还是带动画效果显示出来的。这里，我们可以使用之前介绍过的 Tween 缓动变化类来实现这个过场动画。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token function-variable function">show</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">score<span class="token punctuation">,</span> bestScore</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>scoreLabel<span class="token punctuation">.</span><span class="token function">setText</span><span class="token punctuation">(</span>score<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>bestLabel<span class="token punctuation">.</span><span class="token function">setText</span><span class="token punctuation">(</span>bestScore<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>whiteMask<span class="token punctuation">.</span>alpha <span class="token operator">=</span> <span class="token number">1.0</span><span class="token punctuation">;</span>

    Hilo<span class="token punctuation">.</span>Tween<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>gameover<span class="token punctuation">,</span> <span class="token punctuation">{</span>alpha<span class="token operator">:</span><span class="token number">0</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>duration<span class="token operator">:</span><span class="token number">100</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    Hilo<span class="token punctuation">.</span>Tween<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>board<span class="token punctuation">,</span> <span class="token punctuation">{</span>alpha<span class="token operator">:</span><span class="token number">0</span><span class="token punctuation">,</span> y<span class="token operator">:</span><span class="token keyword">this</span><span class="token punctuation">.</span>board<span class="token punctuation">.</span>y<span class="token operator">+</span><span class="token number">150</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>duration<span class="token operator">:</span><span class="token number">200</span><span class="token punctuation">,</span> delay<span class="token operator">:</span><span class="token number">200</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    Hilo<span class="token punctuation">.</span>Tween<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>scoreLabel<span class="token punctuation">,</span> <span class="token punctuation">{</span>alpha<span class="token operator">:</span><span class="token number">0</span><span class="token punctuation">,</span> y<span class="token operator">:</span><span class="token keyword">this</span><span class="token punctuation">.</span>scoreLabel<span class="token punctuation">.</span>y<span class="token operator">+</span><span class="token number">150</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>duration<span class="token operator">:</span><span class="token number">200</span><span class="token punctuation">,</span> delay<span class="token operator">:</span><span class="token number">200</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    Hilo<span class="token punctuation">.</span>Tween<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>bestLabel<span class="token punctuation">,</span> <span class="token punctuation">{</span>alpha<span class="token operator">:</span><span class="token number">0</span><span class="token punctuation">,</span> y<span class="token operator">:</span><span class="token keyword">this</span><span class="token punctuation">.</span>bestLabel<span class="token punctuation">.</span>y<span class="token operator">+</span><span class="token number">150</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>duration<span class="token operator">:</span><span class="token number">200</span><span class="token punctuation">,</span> delay<span class="token operator">:</span><span class="token number">200</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    Hilo<span class="token punctuation">.</span>Tween<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>startBtn<span class="token punctuation">,</span> <span class="token punctuation">{</span>alpha<span class="token operator">:</span><span class="token number">0</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>duration<span class="token operator">:</span><span class="token number">100</span><span class="token punctuation">,</span> delay<span class="token operator">:</span><span class="token number">600</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    Hilo<span class="token punctuation">.</span>Tween<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>gradeBtn<span class="token punctuation">,</span> <span class="token punctuation">{</span>alpha<span class="token operator">:</span><span class="token number">0</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>duration<span class="token operator">:</span><span class="token number">100</span><span class="token punctuation">,</span> delay<span class="token operator">:</span><span class="token number">600</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    Hilo<span class="token punctuation">.</span>Tween<span class="token punctuation">.</span><span class="token function">to</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>whiteMask<span class="token punctuation">,</span> <span class="token punctuation">{</span>alpha<span class="token operator">:</span><span class="token number">0</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>duration<span class="token operator">:</span><span class="token number">400</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>在游戏主文件 game.js 中，实例化 OverScene 并添加到舞台 stage 上，但结束场景只有游戏结束才显示，因此我们设置其 visible 默认为 false。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">this</span><span class="token punctuation">.</span>gameOverScene <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">game<span class="token punctuation">.</span>OverScene</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  width<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>width<span class="token punctuation">,</span>
  height<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>height<span class="token punctuation">,</span>
  image<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>asset<span class="token punctuation">.</span>over<span class="token punctuation">,</span>
  numberGlyphs<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>asset<span class="token punctuation">.</span>numberGlyphs<span class="token punctuation">,</span>
  visible<span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addTo</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>stage<span class="token punctuation">)</span>
</code></pre></div><p>当点击开始游戏按钮后，游戏会重新回到准备场景。因此，我们需要为它绑定事件监听。而我们不准备显示玩家的等级排行，所以等级按钮无需绑定事件。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">this</span><span class="token punctuation">.</span>gameOverScene<span class="token punctuation">.</span><span class="token function">getChildById</span><span class="token punctuation">(</span><span class="token string">'start'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span>
  Hilo<span class="token punctuation">.</span>event<span class="token punctuation">.</span><span class="token constant">POINTER_START</span><span class="token punctuation">,</span>
  <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">//阻止舞台stage响应后续事件</span>
    e<span class="token punctuation">.</span><span class="token function">stopImmediatePropagation</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>gameOverScene<span class="token punctuation">.</span>visible <span class="token operator">=</span> <span class="token boolean">false</span>
  <span class="token punctuation">}</span><span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span>
<span class="token punctuation">)</span>
</code></pre></div><h3 id="创建小鸟"><a href="#创建小鸟" class="header-anchor">#</a> 创建小鸟</h3> <p>小鸟是游戏的主角，跟其他的对象不同的是，小鸟会扇动翅膀飞行。因此我们用精灵动画类 Sprite 来创建小鸟。这里我们实现一个 Bird 类，继承自 Sprite。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> Bird <span class="token operator">=</span> <span class="token punctuation">(</span>ns<span class="token punctuation">.</span>Bird <span class="token operator">=</span> Hilo<span class="token punctuation">.</span>Class<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  Extends<span class="token operator">:</span> Hilo<span class="token punctuation">.</span>Sprite<span class="token punctuation">,</span>
  <span class="token function-variable function">constructor</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">properties</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    Bird<span class="token punctuation">.</span>superclass<span class="token punctuation">.</span><span class="token function">constructor</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> properties<span class="token punctuation">)</span>

    <span class="token comment">//添加小鸟精灵动画帧</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">addFrame</span><span class="token punctuation">(</span>properties<span class="token punctuation">.</span>atlas<span class="token punctuation">.</span><span class="token function">getSprite</span><span class="token punctuation">(</span><span class="token string">'bird'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token comment">//设置小鸟扇动翅膀的频率</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>interval <span class="token operator">=</span> <span class="token number">6</span>
    <span class="token comment">//设置小鸟的中心点位置</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>pivotX <span class="token operator">=</span> <span class="token number">43</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>pivotY <span class="token operator">=</span> <span class="token number">30</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div><p>小鸟的精灵动画帧可由参数传入的精灵纹理集 atlas 获得。由于小鸟飞行时，身体会向上仰起，也就是会以身体中心点旋转。因此，我们需要设置小鸟的中心点位置 pivotX 和 pivotY，而小鸟的宽度和高度分别为 86 和 60，故 pivotX 和 pivotY 即为 43 和 30。</p> <p>我们发现，在游戏中小鸟一共有以下三个状态：</p> <ul><li>准备状态 - 此时小鸟没有飞行，只是轻微的上下漂浮着。</li> <li>开始飞行 - 每次玩家点击画面时，小鸟就会往上飞一段距离然后下坠。</li> <li>飞行过程 - 在整个飞行过程中，我们需要控制小鸟的姿态和 y 轴坐标（x 轴是不变的）。</li></ul> <p>我们先定义准备状态的 getReady 方法：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token function-variable function">getReady</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token comment">//恢复小鸟飞行角度为平行向前</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>rotation <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
    <span class="token comment">//减慢小鸟精灵动画速率</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>interval <span class="token operator">=</span> <span class="token number">6</span><span class="token punctuation">;</span>
    <span class="token comment">//恢复小鸟精灵动画</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">play</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">//小鸟上下漂浮的动画</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>tween <span class="token operator">=</span> Hilo<span class="token punctuation">.</span>Tween<span class="token punctuation">.</span><span class="token function">to</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>y<span class="token operator">:</span><span class="token keyword">this</span><span class="token punctuation">.</span>y <span class="token operator">+</span> <span class="token number">10</span><span class="token punctuation">,</span> rotation<span class="token operator">:</span><span class="token operator">-</span><span class="token number">8</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>duration<span class="token operator">:</span><span class="token number">400</span><span class="token punctuation">,</span> reverse<span class="token operator">:</span><span class="token boolean">true</span><span class="token punctuation">,</span> loop<span class="token operator">:</span><span class="token boolean">true</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>当玩家点击屏幕后，小鸟开始往上飞行，我们定义 startFly 方法：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token function-variable function">startFly</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token comment">//恢复小鸟状态</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>isDead <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
    <span class="token comment">//减小小鸟精灵动画间隔，加速小鸟扇动翅膀的频率</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>interval <span class="token operator">=</span> <span class="token number">3</span><span class="token punctuation">;</span>
    <span class="token comment">//记录往上飞的起始y轴坐标</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>flyStartY <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>y<span class="token punctuation">;</span>
    <span class="token comment">//记录飞行开始的时间</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>flyStartTime <span class="token operator">=</span> <span class="token operator">+</span><span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">//停止之前的缓动动画</span>
    <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>tween<span class="token punctuation">)</span> <span class="token keyword">this</span><span class="token punctuation">.</span>tween<span class="token punctuation">.</span><span class="token function">stop</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>在这里，我们只需要设置小鸟飞行的初始状态，而具体的飞行状态控制则由 doFly 方法来实现。</p> <p>小鸟开始飞行后，我们需要一个方法来精确控制小鸟每时每刻的飞行的路径坐标，直至其落地死亡。这也是此游戏中最关键的地方之一。</p> <p>我们要在每次游戏画面更新渲染小鸟的时候调用此方法来确定当前时刻小鸟的坐标位置。Hilo 的可视对象 View 提供了一个 onUpdate 方法属性，此方法会在可视对象每次渲染之前调用，于是，我们需要实现小鸟的 onUpdate 方法。</p> <p>每次点击屏幕小鸟会往上飞，这是高中物理中典型的竖直上抛运动。我们发现，小鸟每次都是往上飞行一个固定的高度 flyHeight 后再下坠的。 根据我们以前所学的物理公式：初速度 2 = 2 * 距离 * 加速度，我们可以计算出小鸟往上飞的初速度：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">this</span><span class="token punctuation">.</span>flyHeight <span class="token operator">=</span> <span class="token number">80</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>initVelocity <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">sqrt</span><span class="token punctuation">(</span><span class="token number">2</span> <span class="token operator">*</span> <span class="token keyword">this</span><span class="token punctuation">.</span>flyHeight <span class="token operator">*</span> <span class="token keyword">this</span><span class="token punctuation">.</span>gravity<span class="token punctuation">)</span>
</code></pre></div><p>在这个公式里，flyHeight 已确定，现在要确定加速度 gravity。为简化计算，我们取重力加速 g 为 10m/s2。而在我们游戏里的时间单位是毫秒，我们需要把加速度转换为毫秒，即 10/1000，但实际游戏中并不需要那么大的加速度，比如取一半。因此我们的加速度设定为：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">this</span><span class="token punctuation">.</span>gravity <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">10</span> <span class="token operator">/</span> <span class="token number">1000</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token number">0.3</span>
</code></pre></div><p>有了初速度，我们就可以根据物理公式：位移 = 初速度 * 时间 - 0.5 * 加速度 * 时间 2，计算出任一时刻 time 小鸟移动的距离：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> distance <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>initVelocity <span class="token operator">*</span> time <span class="token operator">-</span> <span class="token number">0.5</span> <span class="token operator">*</span> <span class="token keyword">this</span><span class="token punctuation">.</span>gravity <span class="token operator">*</span> time <span class="token operator">*</span> time
</code></pre></div><p>进而，我们就可以计算出小鸟在任一时刻所在的 y 轴位置：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> y <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>flyStartY <span class="token operator">-</span> distance
</code></pre></div><p>这样，飞行过程的方法 onUpdate 就容易实现了：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token function-variable function">onUpdate</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>isDead<span class="token punctuation">)</span> <span class="token keyword">return</span><span class="token punctuation">;</span>

    <span class="token comment">//飞行时间</span>
    <span class="token keyword">var</span> time <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token operator">+</span><span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token keyword">this</span><span class="token punctuation">.</span>flyStartTime<span class="token punctuation">;</span>
    <span class="token comment">//飞行距离</span>
    <span class="token keyword">var</span> distance <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>initVelocity <span class="token operator">*</span> time <span class="token operator">-</span> <span class="token number">0.5</span> <span class="token operator">*</span> <span class="token keyword">this</span><span class="token punctuation">.</span>gravity <span class="token operator">*</span> time <span class="token operator">*</span> time<span class="token punctuation">;</span>
    <span class="token comment">//y轴坐标</span>
    <span class="token keyword">var</span> y <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>flyStart <span class="token operator">-</span> distance<span class="token punctuation">;</span>

    <span class="token keyword">if</span><span class="token punctuation">(</span>y <span class="token operator">&lt;=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>groundY<span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token comment">//小鸟未落地</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>y <span class="token operator">=</span> y<span class="token punctuation">;</span>
        <span class="token keyword">if</span><span class="token punctuation">(</span>distance <span class="token operator">&gt;</span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span><span class="token keyword">this</span><span class="token punctuation">.</span>isUp<span class="token punctuation">)</span><span class="token punctuation">{</span>
            <span class="token comment">//往上飞时，角度上仰20度</span>
            <span class="token keyword">this</span><span class="token punctuation">.</span>tween <span class="token operator">=</span> Hilo<span class="token punctuation">.</span>Tween<span class="token punctuation">.</span><span class="token function">to</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>rotation<span class="token operator">:</span><span class="token operator">-</span><span class="token number">20</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>duration<span class="token operator">:</span><span class="token number">200</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">this</span><span class="token punctuation">.</span>isUp <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token keyword">else</span> <span class="token keyword">if</span><span class="token punctuation">(</span>distance <span class="token operator">&lt;</span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>isUp<span class="token punctuation">)</span><span class="token punctuation">{</span>
            <span class="token comment">//往下跌落时，角度往下90度</span>
            <span class="token keyword">this</span><span class="token punctuation">.</span>tween <span class="token operator">=</span> Hilo<span class="token punctuation">.</span>Tween<span class="token punctuation">.</span><span class="token function">to</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>rotation<span class="token operator">:</span><span class="token number">90</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>duration<span class="token operator">:</span><span class="token keyword">this</span><span class="token punctuation">.</span>groundY <span class="token operator">-</span> <span class="token keyword">this</span><span class="token punctuation">.</span>y<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">this</span><span class="token punctuation">.</span>isUp <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token keyword">else</span><span class="token punctuation">{</span>
        <span class="token comment">//小鸟已经落地，即死亡</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>y <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>groundY<span class="token punctuation">;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>isDead <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>其中，当小鸟往上飞的时候，有一个抬头往上仰的动作；而往下跌落的时候，则是会头部往下栽。我们使用 2 个缓动变换 tween 来分别实现。</p> <h3 id="创建障碍"><a href="#创建障碍" class="header-anchor">#</a> 创建障碍</h3> <p>障碍是游戏中另一个非常重要的角色。整个障碍是由许多成对的上下管子组成。因此我们用容器类来创建障碍类，它可以装下许多管子。这里我们实现一个 Holdbacks 类，继承自 Container。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> Holdbacks <span class="token operator">=</span> <span class="token punctuation">(</span>ns<span class="token punctuation">.</span>Holdbacks <span class="token operator">=</span> Hilo<span class="token punctuation">.</span>Class<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  Extends<span class="token operator">:</span> Hilo<span class="token punctuation">.</span>Container<span class="token punctuation">,</span>
  <span class="token function-variable function">constructor</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">properties</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    Holdbacks<span class="token punctuation">.</span>superclass<span class="token punctuation">.</span><span class="token function">constructor</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> properties<span class="token punctuation">)</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">init</span><span class="token punctuation">(</span>properties<span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div><p>然后，我们准备构造这些障碍管子。一个事实是，这些管子是不间断的从右到左移动的，这些管子之间的水平距离是固定的，样式也是不变的。如果我们能重复利用这些管子，那么我们可以节省很多内存。这样，我们先初始化一些常量：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">//管子之间的水平间隔</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>hoseSpacingX <span class="token operator">=</span> <span class="token number">300</span>
<span class="token comment">//管子上下两部分之间的垂直间隔，即小鸟要穿越的空间大小</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>hoseSpacingY <span class="token operator">=</span> <span class="token number">240</span>
<span class="token comment">//管子的总数（一根管子分上下两部分）</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>numHoses <span class="token operator">=</span> <span class="token number">4</span>
<span class="token comment">//预设移出屏幕左侧的管子数量，一般设置为管子总数的一半</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>numOffscreenHoses <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>numHoses <span class="token operator">*</span> <span class="token number">0.5</span>
<span class="token comment">//管子的宽度（包括管子之间的间隔）</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>hoseWidth <span class="token operator">=</span> <span class="token number">148</span> <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span>hoseSpacingX

<span class="token comment">//初始化障碍的宽和高</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>width <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>hoseWidth <span class="token operator">*</span> <span class="token keyword">this</span><span class="token punctuation">.</span>numHoses
<span class="token keyword">this</span><span class="token punctuation">.</span>height <span class="token operator">=</span> properties<span class="token punctuation">.</span>height
</code></pre></div><p>下面，我们创建所有的管子，包括用来缓存的。其中每根管子包括上下两部分，而每根管子都是静态图片，因此我们使用 Bitmap 类来创建管子。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token function-variable function">createHoses</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">image</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>numHoses<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token comment">//下部分管子</span>
        <span class="token keyword">var</span> downHose <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Hilo<span class="token punctuation">.</span>Bitmap</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
            image<span class="token operator">:</span> image<span class="token punctuation">,</span>
            rect<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">148</span><span class="token punctuation">,</span> <span class="token number">820</span><span class="token punctuation">]</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addTo</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">//上部分管子</span>
        <span class="token keyword">var</span> upHose <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Hilo<span class="token punctuation">.</span>Bitmap</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
            image<span class="token operator">:</span> image<span class="token punctuation">,</span>
            rect<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">148</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">148</span><span class="token punctuation">,</span> <span class="token number">820</span><span class="token punctuation">]</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addTo</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">placeHose</span><span class="token punctuation">(</span>downHose<span class="token punctuation">,</span> upHose<span class="token punctuation">,</span> i<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>创建好管子后，我们需要放置在适当的位置上，从而产生随机可穿越的管子障碍。我们先来看管子的下半部分，如果我们能确定它在 y 轴上的最大值和最小值，那么就可以在此之间选择一个随机值。当下半部分管子的位置确定后，由于管子上下两部分的间隔 hoseSpacingY 是固定的。这样就很容易确定上部分管子的位置了。</p> <p>由于下半部分管子的顶端不能没入地面之下，且不能离地面太近，因此很容易计算出其 y 轴的最大值为：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> downMaxY <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>groundY <span class="token operator">-</span> <span class="token number">180</span>
</code></pre></div><p>同样下半部分管子的底端也不能脱离地面，且要预留间隔 hoseSpacingY 的高度，因此其 y 轴的最小值为：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> downMinY <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>groundY <span class="token operator">-</span> down<span class="token punctuation">.</span>height <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span>hoseSpacingY
</code></pre></div><p>在最大值和最小值之间随机选择一个位置：</p> <div class="language-js extra-class"><pre class="language-js"><code>downHose<span class="token punctuation">.</span>y <span class="token operator">=</span> <span class="token punctuation">(</span>downMinY <span class="token operator">+</span> <span class="token punctuation">(</span>downMaxY <span class="token operator">-</span> downMinY<span class="token punctuation">)</span> <span class="token operator">*</span> Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">&gt;&gt;</span> <span class="token number">0</span>
</code></pre></div><p>下半部分管子位置确定后，上半部分就好办了。完整的 placeHose 方法：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token function-variable function">placeHose</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">down<span class="token punctuation">,</span> up<span class="token punctuation">,</span> index</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token comment">//y轴最大值</span>
    <span class="token keyword">var</span> downMaxY <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>groundY <span class="token operator">-</span> <span class="token number">180</span><span class="token punctuation">;</span>
    <span class="token comment">//y轴最小值</span>
    <span class="token keyword">var</span> downMinY <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>groundY <span class="token operator">-</span> down<span class="token punctuation">.</span>height <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span>hoseSpacingY<span class="token punctuation">;</span>
    <span class="token comment">//随机位置</span>
    down<span class="token punctuation">.</span>y <span class="token operator">=</span> downMinY <span class="token operator">+</span> <span class="token punctuation">(</span>downMaxY <span class="token operator">-</span> downMinY<span class="token punctuation">)</span> <span class="token operator">*</span> Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&gt;&gt;</span> <span class="token number">0</span><span class="token punctuation">;</span>
    down<span class="token punctuation">.</span>x <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>hoseWidth <span class="token operator">*</span> index<span class="token punctuation">;</span>

    <span class="token comment">//上部分管子位置</span>
    up<span class="token punctuation">.</span>y <span class="token operator">=</span> down<span class="token punctuation">.</span>y <span class="token operator">-</span> <span class="token keyword">this</span><span class="token punctuation">.</span>hoseSpacingY <span class="token operator">-</span> up<span class="token punctuation">.</span>height<span class="token punctuation">;</span>
    up<span class="token punctuation">.</span>x <span class="token operator">=</span> down<span class="token punctuation">.</span>x<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>障碍创建完成后，它最核心的状态就是从右至左不断的移动，管子也不断的产生。我们先初始化一个移动的缓动 moveTween，当缓动结束后，就会调用 resetHoses 方法来重新排序所有的管子，从而达到重复利用管子的目的。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">this</span><span class="token punctuation">.</span>moveTween <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Hilo<span class="token punctuation">.</span>Tween</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
  onComplete<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">resetHoses</span><span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div><p>resetHoses 方法要实现的就是，每当有 numOffscreenHoses 数量的管子移出屏幕左侧的时候，我们就把这些管子移动到管子队列的最右边，这样我们就可以利用移出的管子，不用重复创建新的管子。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token function-variable function">resetHoses</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">var</span> total <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>numChildren<span class="token punctuation">;</span>

    <span class="token comment">//把已移出屏幕外的管子放到队列最后面，并重置它们的可穿越位置</span>
    <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>numOffscreenHoses<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token keyword">var</span> downHose <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getChildAt</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">var</span> upHose <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getChildAt</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setChildIndex</span><span class="token punctuation">(</span>downHose<span class="token punctuation">,</span> total <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setChildIndex</span><span class="token punctuation">(</span>upHose<span class="token punctuation">,</span> total <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">placeHose</span><span class="token punctuation">(</span>downHose<span class="token punctuation">,</span> upHose<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>numOffscreenHoses <span class="token operator">+</span> i<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">//重新确定队列中所有管子的x轴坐标</span>
    <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> total <span class="token operator">-</span> <span class="token keyword">this</span><span class="token punctuation">.</span>numOffscreenHoses <span class="token operator">*</span> <span class="token number">2</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token keyword">var</span> hose <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getChildAt</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">;</span>
        hose<span class="token punctuation">.</span>x <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>hoseWidth <span class="token operator">*</span> <span class="token punctuation">(</span>i <span class="token operator">*</span> <span class="token number">0.5</span> <span class="token operator">&gt;&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">//重新确定障碍的x轴坐标</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>x <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>

    <span class="token comment">//更新穿过的管子数量</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>passThrough <span class="token operator">+=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>numOffscreenHoses<span class="token punctuation">;</span>

    <span class="token comment">//继续移动</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">startMove</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>这样，移动障碍也就是重复不断的向左移出 <code>numOffscreenHoses</code> 数量的管子。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token function-variable function">startMove</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token comment">//设置缓动的x轴坐标</span>
    <span class="token keyword">var</span> targetX <span class="token operator">=</span> <span class="token operator">-</span><span class="token keyword">this</span><span class="token punctuation">.</span>hoseWidth <span class="token operator">*</span> <span class="token keyword">this</span><span class="token punctuation">.</span>numOffscreenHoses<span class="token punctuation">;</span>
    <span class="token comment">//设置缓动时间</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>moveTween<span class="token punctuation">.</span>time <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>x <span class="token operator">-</span> targetX<span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token number">4</span><span class="token punctuation">;</span>
    <span class="token comment">//设置缓动的变换属性，即x从当前坐标变换到targetX</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>moveTween<span class="token punctuation">.</span><span class="token function">setProps</span><span class="token punctuation">(</span><span class="token punctuation">{</span>x<span class="token operator">:</span><span class="token keyword">this</span><span class="token punctuation">.</span>x<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>x<span class="token operator">:</span>targetX<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">//启动缓动变换</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>moveTween<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>停止移动障碍就只需停止缓动即可。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token function-variable function">stopMove</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>moveTween<span class="token punctuation">)</span> <span class="token keyword">this</span><span class="token punctuation">.</span>moveTween<span class="token punctuation">.</span><span class="token function">pause</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><h3 id="碰撞检测和得分"><a href="#碰撞检测和得分" class="header-anchor">#</a> 碰撞检测和得分</h3> <p>当小鸟飞行穿越障碍的时候，我们需要检测小鸟与障碍是否发生了碰撞。这个可以利用 Hilo 内置的 <code>View.hitTestObject</code> 方法来检测。我们在障碍 Holdbacks 类中定义 checkCollision 方法，它可以循环检测小鸟是否与某一管子发生碰撞。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token function-variable function">checkCollision</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">bird</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">,</span> len <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>children<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i <span class="token operator">&lt;</span> len<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token keyword">if</span><span class="token punctuation">(</span>bird<span class="token punctuation">.</span><span class="token function">hitTestObject</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>children<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
            <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>得分，也就是计算出小鸟飞越的管子的数量。我们定义 calcPassThrough 方法，它传入一个参数 x（小鸟的坐标），根据障碍的宽度和已穿越的管子的数量，我们就可以统计出总的数量。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token function-variable function">calcPassThrough</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">x</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">var</span> count <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>

    x <span class="token operator">=</span> <span class="token operator">-</span><span class="token keyword">this</span><span class="token punctuation">.</span>x <span class="token operator">+</span> x<span class="token punctuation">;</span>
    <span class="token keyword">if</span><span class="token punctuation">(</span>x <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token keyword">var</span> num <span class="token operator">=</span> x <span class="token operator">/</span> <span class="token keyword">this</span><span class="token punctuation">.</span>hoseWidth <span class="token operator">+</span> <span class="token number">0.5</span> <span class="token operator">&gt;&gt;</span> <span class="token number">0</span><span class="token punctuation">;</span>
        count <span class="token operator">+=</span> num<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    count <span class="token operator">+=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>passThrough<span class="token punctuation">;</span>

    <span class="token keyword">return</span> count<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>然后，在 game.js 中计算得分：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token function-variable function">calcScore</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">var</span> count <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>holdbacks<span class="token punctuation">.</span><span class="token function">calcPassThrough</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>bird<span class="token punctuation">.</span>x<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>score <span class="token operator">=</span> count<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><h3 id="监控游戏过程"><a href="#监控游戏过程" class="header-anchor">#</a> 监控游戏过程</h3> <p>在游戏过程中，我们要时刻检测小鸟是否与障碍发生碰撞或飞越成功，是否已经落地，并判断游戏是否结束等。跟小鸟飞行过程类似，我们可以定义舞台的 onUpdate 方法来实现：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token function-variable function">onUpdate</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>state <span class="token operator">===</span> <span class="token string">'ready'</span><span class="token punctuation">)</span> <span class="token keyword">return</span><span class="token punctuation">;</span>

    <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>bird<span class="token punctuation">.</span>isDead<span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token comment">//如果小鸟死亡，则游戏结束</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">gameOver</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token keyword">else</span><span class="token punctuation">{</span>
        <span class="token comment">//更新玩家得分</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>currentScore<span class="token punctuation">.</span><span class="token function">setText</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">calcScore</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">//碰撞检测</span>
        <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>holdbacks<span class="token punctuation">.</span><span class="token function">checkCollision</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>bird<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
            <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">gameOver</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><h3 id="场景切换"><a href="#场景切换" class="header-anchor">#</a> 场景切换</h3> <p>准备、游戏和结束三个场景的切换方法：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token function-variable function">gameReady</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>state <span class="token operator">=</span> <span class="token string">'ready'</span><span class="token punctuation">;</span>
    <span class="token comment">//重置分数为0</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>score <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>currentScore<span class="token punctuation">.</span>visible <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>currentScore<span class="token punctuation">.</span><span class="token function">setText</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>score<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">//显示准备场景</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>gameReadyScene<span class="token punctuation">.</span>visible <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
    <span class="token comment">//重置障碍的位置</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>holdbacks<span class="token punctuation">.</span><span class="token function">reset</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">//准备小鸟</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>bird<span class="token punctuation">.</span><span class="token function">getReady</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>

<span class="token function-variable function">gameStart</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>state <span class="token operator">=</span> <span class="token string">'playing'</span><span class="token punctuation">;</span>
    <span class="token comment">//隐藏准备场景</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>gameReadyScene<span class="token punctuation">.</span>visible <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
    <span class="token comment">//开始从右至左移动障碍</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>holdbacks<span class="token punctuation">.</span><span class="token function">startMove</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>

<span class="token function-variable function">gameOver</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>state <span class="token operator">!==</span> <span class="token string">'over'</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token comment">//设置当前状态为结束over</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>state <span class="token operator">=</span> <span class="token string">'over'</span><span class="token punctuation">;</span>
        <span class="token comment">//停止障碍的移动</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>holdbacks<span class="token punctuation">.</span><span class="token function">stopMove</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">//小鸟跳转到第一帧并暂停，即停止扇动翅膀</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>bird<span class="token punctuation">.</span><span class="token function">goto</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">//隐藏屏幕中间显示的分数</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>currentScore<span class="token punctuation">.</span>visible <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
        <span class="token comment">//显示结束场景</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>gameOverScene<span class="token punctuation">.</span><span class="token function">show</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">calcScore</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">saveBestScore</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><h3 id="玩家交互"><a href="#玩家交互" class="header-anchor">#</a> 玩家交互</h3> <p>在此游戏中，玩家只有一种交互方式，在 PC 端是点击鼠标，在移动端则是触碰屏幕。因此，首先我们需要让舞台 stage 能接受 mousedown 或 touchstart 事件：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">this</span><span class="token punctuation">.</span>stage<span class="token punctuation">.</span><span class="token function">enableDOMEvent</span><span class="token punctuation">(</span>Hilo<span class="token punctuation">.</span>event<span class="token punctuation">.</span><span class="token constant">POINTER_START</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span>
</code></pre></div><p>Hilo 统一了事件的开始、移动和结束三个事件的映射名称，方便自动适配不同平台：</p> <ul><li><code>Hilo.event.POINTER_START</code> - mousedown/touchstart</li> <li><code>Hilo.event.POINTER_MOVE</code> - mousemove/touchmove</li> <li><code>Hilo.event.POINTER_END</code> - mouseup/touchend</li></ul> <p>然后，监听舞台的 POINTER_START 事件：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">this</span><span class="token punctuation">.</span>stage<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span>Hilo<span class="token punctuation">.</span>event<span class="token punctuation">.</span><span class="token constant">POINTER_START</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">onUserInput</span><span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div><p>为了让 PC 玩家可以使用键盘空格键操作，我们增加如下兼容代码：</p> <div class="language-js extra-class"><pre class="language-js"><code>document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span>
  <span class="token string">'keydown'</span><span class="token punctuation">,</span>
  <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>e<span class="token punctuation">.</span>keyCode <span class="token operator">===</span> <span class="token number">32</span><span class="token punctuation">)</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">onUserInput</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span>
<span class="token punctuation">)</span>
</code></pre></div><p>事件监听器 onUserInput 的实现也简单，当游戏不在结束状态时，启动游戏，并控制小鸟往上飞。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token function-variable function">onUserInput</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>state <span class="token operator">!==</span> <span class="token string">'over'</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token comment">//启动游戏场景</span>
        <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>state <span class="token operator">!==</span> <span class="token string">'playing'</span><span class="token punctuation">)</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">gameStart</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">//控制小鸟往上飞</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>bird<span class="token punctuation">.</span><span class="token function">startFly</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><h3 id="小结"><a href="#小结" class="header-anchor">#</a> 小结</h3> <p>至此，整个 Flappy Bird 游戏所有的功能就基本开发完成了。我们用到了 Hilo 的大部分功能：</p> <ul><li>加载队列 - 用 LoadQueue 预加载图片等资源。</li> <li>可视对象 - 用 View、Bitmap、Sprite、Container 等创建和管理各种游戏对象。</li> <li>舞台 - 所有游戏对象都需要加入到舞台才能显示出来。</li> <li>缓动动画 - 用 Tween 来创建各种缓动动画。</li> <li>碰撞检测 - 用 View.hitTestObject 检测可视对象的是否发生碰撞。</li> <li>更新对象 - 用 View.onUpdate 更新对象各种属性和状态。</li> <li>事件交互 - 用 View.on 监听事件。</li></ul></div> <footer class="page-edit"><!----> <div class="last-updated"><span class="prefix">更新于:</span> <span class="time">9/11/2020, 8:28:39 PM</span></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
      ←
      <a href="/practice/deepL.html" class="prev">
        使用pytorch进行深度学习
      </a></span> <span class="next"><a href="/practice/canvas.html">
        canvas 绘制
      </a>
      →
    </span></p></div> </main></div><div class="global-ui"><!----></div></div>
    <script src="/assets/js/app.9e067b79.js" defer></script><script src="/assets/js/2.983eb755.js" defer></script><script src="/assets/js/60.b47b75bb.js" defer></script>
  </body>
</html>
